package vertxZeebe;

import io.vertx.core.AbstractVerticle;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.RoutingContext;
import io.vertx.ext.web.api.RequestParameters;
import io.vertx.ext.web.api.contract.openapi3.OpenAPI3RouterFactory;
import io.vertx.serviceproxy.ServiceException;
import io.zeebe.client.ZeebeClient;
import vertxZeebe.jobworker.GJobWorker;
import vertxZeebe.jobworker.HumanTaskJobWorker;
import vertxZeebe.jobworker.RJobWorker;
import vertxZeebe.service.PgService;

import java.util.*;

public class HumanTaskVertx extends AbstractVerticle {

    ZeebeClient client;
    PgService pgService;
    JsonObject userMap = new JsonObject();
    JsonObject groupMap = new JsonObject();

    @Override
    public void start() {
        //0.初始化用户和组--这里用map代替
        userMap.put("0", "admin");
        userMap.put("1", "john");
        userMap.put("2", "anna");
        userMap.put("3", "frank");
        userMap.put("4", "alice");
        JsonArray employeeSet = new JsonArray();
        employeeSet.add(000003L);
        employeeSet.add(000004L);
        groupMap.put("employee", employeeSet);

        //1.初始化zeebeClient
        client = ZeebeClient
                .newClientBuilder()
                .brokerContactPoint("localhost:26500")
                .usePlaintext()
                .build();

        //2.初始化PgService
        pgService = new PgService(vertx);

        //3.部署一个jobworker,人工任务如果做成公共模块，则不能够在代码中写死jobworker需要获取的参数。
        GJobWorker gJobWorker = new GJobWorker(client);
        client.newWorker()
                .jobType("G")
                .handler(gJobWorker)
                .open();
        HumanTaskJobWorker humanTaskJobWorker = new HumanTaskJobWorker(pgService);
        client.newWorker()
                .jobType("human")
                .handler(humanTaskJobWorker)
                .open();
        List<String> list = Arrays.asList("res1", "res2", "res3");
        RJobWorker rJobWorker = new RJobWorker(client);
        client.newWorker()
                .jobType("R")
                .handler(rJobWorker)
                .fetchVariables(list)
                .open();

        //4.启动一个webServer
        Router router = Router.router(vertx);

        //5.创建routerfactory
        OpenAPI3RouterFactory.create(vertx, "api/humanTaskOpenApi.yml", ar -> {
            if (ar.succeeded()) {
                OpenAPI3RouterFactory routerFactory = ar.result();

                routerFactory.addHandlerByOperationId("humanTaskComplete", this::humanTaskComplete);
                routerFactory.addHandlerByOperationId("humanTaskClaim", this::humanTaskClaim);
                routerFactory.addHandlerByOperationId("setHumanTaskEndTime", this::setHumanTaskEndTime);
                routerFactory.addHandlerByOperationId("assignTask", this::assignTask);
                router.mountSubRouter("/xj", routerFactory.getRouter());
                vertx.createHttpServer()
                        .requestHandler(router)
                        .listen(8888);
            } else {
                System.out.println("加载api文件失败：" + ar.cause());
            }
        });
    }

    /**
     * 完成任务
     *
     * @param context
     */
    private void humanTaskComplete(RoutingContext context) {
        RequestParameters params = context.get("parsedParameters");
        Long jobKey = params.pathParameter("jobKey").getLong();

        pgService.humanTaskComplete(jobKey, ar -> {
            if (ar.succeeded()) {
                JsonObject result = new JsonObject().put("humanTaskResult", params.body().getJsonObject().encode());
                client.newCompleteCommand(jobKey).variables(result.encode()).send().join();
                context.response().end(jobKey + "人工任务执行完成");
            } else {
                context.fail(ar.cause());
            }
        });
    }

    /**
     * 声明任务
     *
     * @param context
     */
    private void humanTaskClaim(RoutingContext context) {
        RequestParameters params = context.get("parsedParameters");
        Long userId = params.headerParameter("userId").getLong();
        Long jobKey = params.pathParameter("jobKey").getLong();

        //验证是否是真正的用户--这里用map代替
        if (userMap.getString(String.valueOf(userId)) != null) {
            pgService.humanTaskClaim(jobKey, userId, groupMap, ar -> {
                if (ar.succeeded()) {
                    context.response().end(userId + "用户声明" + jobKey + "人工任务成功");
                } else {
                    context.fail(ar.cause());
                }
            });
        } else {
            context.fail(new ServiceException(400, "No user found with userId: " + userId,
                    new JsonObject().put("message", "No user found with userId: " + userId))
            );
        }
    }

    /**
     * 设置任务的截止时间，如果任务已完成，则无需修改
     *
     * @param context
     */
    private void setHumanTaskEndTime(RoutingContext context) {
        RequestParameters params = context.get("parsedParameters");
        Long jobkey = params.pathParameter("jobKey").getLong();
        Long seconds = params.queryParameter("seconds").getLong();
        Long userId = params.headerParameter("userId").getLong();

        if (userMap.getString("" + userId).equals("admin")) {
            pgService.setHumanTaskEndTime(jobkey, seconds, ar -> {
                if (ar.succeeded()) {
                    context.response().end(ar.result().toString());
                } else {
                    context.fail(ar.cause());
                }
            });
        } else {
            context.fail(new ServiceException(400, "only admin user can set task endTime",
                    new JsonObject().put("message", "only admin user can set task endTime"))
            );
        }
    }

    private void assignTask(RoutingContext context) {
        RequestParameters params = context.get("parsedParameters");
        Long jobKey = params.pathParameter("jobKey").getLong();
        Long assignee = params.pathParameter("assignee").getLong();
        Long userId = params.headerParameter("userId").getLong();

        //判断userId和assignedId是否存在
        if (userMap.getString("" + userId) == null || userMap.getString("" + assignee) == null) {
            context.fail(new ServiceException(400, "分配任务的人员或者被分配用户不存在！",
                    new JsonObject().put("message", "分配任务的人员或者被分配用户不存在!")));
            return;
        }

        pgService.assignTask(jobKey, userId, assignee, userMap, groupMap, ar -> {
            if (ar.succeeded()) {
                context.response().end(ar.result().toString());
            } else {
                context.fail(ar.cause());
            }
        });
    }
}
